package com.test.test;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import lombok.extern.slf4j.Slf4j;

@Controller
@RequestMapping("/word")
@Slf4j
public class WordController {


    /**
     * 将文件以流的形式一次性读取到内存，通过响应输出流输出到前端
     * http://localhost:8080/word/export01
     * 这种方式文件太大时会内存溢出
     */
    @ResponseBody
    @GetMapping("export01")
    public void export(HttpServletResponse response) throws IOException {
        // path是指想要下载的文件的路径
        final String path = "G:\\vm\\centos82_2004\\centos82-s002.vmdk";
        File file = new File(path);
        log.info(file.getPath());
        // 获取文件名
        String filename = file.getName();
        // 获取文件后缀名
        String ext = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
        log.info("文件后缀名：" + ext);

        // 将文件写入输入流
        FileInputStream fileInputStream = new FileInputStream(file);
        InputStream fis = new BufferedInputStream(fileInputStream);
        byte[] buffer = new byte[fis.available()];
        fis.read(buffer);
        fis.close();

        // 清空response
        response.reset();
        // 设置response的Header
        response.setCharacterEncoding("UTF-8");
        //Content-Disposition的作用：告知浏览器以何种方式显示响应返回的文件，用浏览器打开还是以附件的形式下载到本地保存
        //attachment表示以附件方式下载   inline表示在线打开   "Content-Disposition: inline; filename=文件名.mp3"
        // filename表示文件的默认名称，因为网络传输只支持URL编码的相关支付，因此需要将文件名URL编码后进行传输,前端收到后需要反编码才能获取到真正的名称
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("中文文件名称.txt", "UTF-8"));
        // 告知浏览器文件的大小
        response.addHeader("Content-Length", "" + file.length());
        OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
        response.setContentType("application/octet-stream");
        outputStream.write(buffer);
        outputStream.flush();
    }


    /**
     * 将输入流中的数据循环写入到响应输出流中，而不是一次性读取到内存，通过响应输出流输出到前端
     * http://localhost:8080/word/export02
     */
    @ResponseBody
    @GetMapping("export02")
    public void export02(HttpServletResponse response) throws IOException {
        // path是指想要下载的文件的路径
        final String path = "G:\\vm\\centos82_2004\\centos82-s002.vmdk";
        // 将文件写入输入流
        response.setContentType("application/octet-stream");
        response.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("中文文件名称.txt", "UTF-8"));
        try (FileInputStream inputStream  = new FileInputStream(path)) {
            ServletOutputStream outputStream = response.getOutputStream();
            byte[] b = new byte[1024];
            int len;
            //从输入流中读取一定数量的字节，并将其存储在缓冲区字节数组中，读到末尾返回-1
            while ((len = inputStream.read(b)) > 0) {
                outputStream.write(b, 0, len);
            }
        }
    }


    /**
     * 将输入流中的数据循环写入到响应输出流中，而不是一次性读取到内存，通过响应输出流输出到前端
     * http://localhost:8080/word/export03
     * @return
     */
    @ResponseBody
    @GetMapping("export03")
    public void export03(HttpServletResponse response) throws IOException {
        // path是指想要下载的文件的路径
        final String path = "G:\\vm\\centos82_2004\\centos82-s002.vmdk";
        // 将文件写入输入流
        response.setContentType("application/octet-stream");
        response.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("中文文件名称.txt", "UTF-8"));
        FileInputStream inputStream  = new FileInputStream(path);
        // 这个也是不会内存溢出的
        IOUtils.copy(inputStream, response.getOutputStream());
    }

    /**
     * 将输入流中的数据循环写入到响应输出流中，而不是一次性读取到内存，通过响应输出流输出到前端
     * http://localhost:8080/word/export04
     * @return
     */
    @ResponseBody
    @GetMapping("export04")
    public ResponseEntity export04() throws IOException {
        // path是指想要下载的文件的路径
        final String path = "G:\\vm\\centos82_2004\\centos82-s002.vmdk";

        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + URLEncoder.encode("中文文件名称.txt", "UTF-8"))
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(new FileInputStream(path));

    }
}
